﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cool.Application.System.UserService.Dtos;
using Cool.Core;
using Cool.Core.DataExtensions;
using Cool.Core.Entities.System;
using Cool.Core.Enums;
using Cool.Core.Managers;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Cool.Application.System.UserService
{
    [Authorize]
    [ApiDescriptionSettings("System")]
    [Route("api/system/[controller]")]
    public class UserService:IUserService, ITransient, IDynamicApiController
    {

        /// <summary>
        /// 部门仓储
        /// </summary>
        private readonly IRepository<SysDept> _deptRepository;

        /// <summary>
        /// 用户仓储
        /// </summary>
        private readonly IRepository<SysUser> _userRepository;

        /// <summary>
        /// 岗位仓储
        /// </summary>
        private readonly IRepository<SysPost> _postRepository;

        /// <summary>
        /// 用户岗位仓储
        /// </summary>
        private readonly IRepository<SysUserPost> _userPostRepository;

        /// <summary>
        /// 角色仓储
        /// </summary>
        private readonly IRepository<SysRole> _roleRepository;

        /// <summary>
        /// 用户角色仓储
        /// </summary>
        private readonly IRepository<SysUserRole> _userRoleRepository;

        /// <summary>
        /// 用户管理类
        /// </summary>
        private readonly IUserManager _userManager;

        /// <summary>
        /// 菜单仓储
        /// </summary>
        private readonly IRepository<SysMenu> _menuRepository;

        /// <summary>
        /// 角色菜单配置仓储
        /// </summary>
        private readonly IRepository<SysRoleMenu> _roleMenuRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="userRepository"></param>
        /// <param name="userManager"></param>
        public UserService(IRepository<SysUser> userRepository, IUserManager userManager, 
            IRepository<SysDept> deptRepository,
            IRepository<SysPost> postRepository,
            IRepository<SysRole> roleRepository,
            IRepository<SysUserRole> userRoleRepository,
            IRepository<SysUserPost> userPostRepository,
            IRepository<SysMenu> menuRepository, 
            IRepository<SysRoleMenu> roleMenuRepository)
        {
            _userRepository = userRepository;
            _userManager = userManager;
            _deptRepository = deptRepository;
            _postRepository = postRepository;
            _roleRepository = roleRepository;
            _userRoleRepository = userRoleRepository;
            _userPostRepository = userPostRepository;
            _menuRepository = menuRepository;
            _roleMenuRepository = roleMenuRepository;
        }
        /// <summary>
        /// 获取所有用户列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [ HttpGet, ApiDescriptionSettings(Name = "list")]
        public async Task<PagedList<UserProfile>> GetListAsync([FromQuery, Required] GetUserListInput input)
        {
            var hasKeyword = !string.IsNullOrEmpty(input.UserName?.Trim());
            var hasStatus = input.Status != null;

            var userPages = await (from user in _userRepository.AsQueryable()
                    join dept in _deptRepository.AsQueryable() on user.DeptId equals dept.Id
                    orderby user.CreatedTime descending
                    select new UserProfile()
                    {
                        Id=user.Id,
                        UserName=user.UserName,
                        NickName = user.NickName,
                        DeptId = user.DeptId,
                        DeptName =dept.DeptName,
                        PhoneNumber=user.PhoneNumber,
                        CreatedTime=user.CreatedTime,
                        Status = user.Status,
                        UserType=user.UserType
                    }).Where(
                    (hasKeyword, u => EF.Functions.Like(u.UserName, $"%{input.UserName.Trim()}%")),
                    (hasKeyword, u => EF.Functions.Like(u.NickName, $"%{input.UserName.Trim()}%")),
                    (input.DeptId!=null, u => u.DeptId==input.DeptId),
                    (hasStatus, u => u.Status == input.Status)
                ).ToDeptPermsList().ToPagedListAsync(input.PageIndex, input.PageSize);
                //.Skip(input.PageSize * (input.PageIndex - 1)).Take(input.PageSize)
            return userPages.Adapt<PagedList<UserProfile>>();
        }

        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine(SecurityConsts.USER_SERVICE_ADD)]
        public async Task<UserProfile> AddAsync([Required] UserProfile input)
        {
            // 判断账号是否存在
            var isExist = await _userRepository.AnyAsync(u => u.UserName.ToLower() == input.UserName.Trim().ToLower());
            if (isExist) throw Oops.Oh(SystemErrorCodes.u1003);
            using (var transaction = _userRepository.Database.BeginTransaction())
            {
                try
                {
                    var addUser = input.Adapt<SysUser>();
                    addUser.Password = MD5Encryption.Encrypt(input.Pwd);


                    var entryEntity = await _userRepository.InsertNowAsync(addUser);
                    input.Id = entryEntity.Entity.Id;
                    SavePostOrRoleInfo(input);
                    // 提交事务
                    transaction.Commit();
                    return entryEntity.Entity.Adapt<UserProfile>();
                }
                catch (Exception e)
                {
                    transaction.Rollback();
                    return null;
                }
            }

            
        }

        public dynamic Profile()
        {
            var userInfo= _userManager.User;
            var roleIds = _userManager.Roles.Select(p => p.Id).ToList();

            var permissions = (from roleMenu in _roleMenuRepository.AsQueryable()
                join menu in _menuRepository.AsQueryable() on roleMenu.MenuId equals menu.Id
                where menu.MenuType == 'F' && roleIds.Contains(roleMenu.RoleId)
                select menu.Perms).Distinct();
            return new
            {
                username=userInfo.UserName,
                permissions = permissions.ToList(),
                roles = _userManager.Roles.Select(p=>p.RoleKey),
                avatar = new string[] { "https://i.gtimg.cn/club/item/face/img/2/15922_100.gif" }
            };
        }

        public dynamic GetAsync([FromQuery] int? userId)
        {
            UserProfile userProfile = null;
            if (userId!=null)
            {
                var user = _userRepository.Find(userId);
                userProfile = user.Adapt<UserProfile>();
                userProfile.postIds =
                    _userPostRepository.Where(p => p.UserId == userId).Select(p => p.PostId).ToList();
                userProfile.roleIds = 
                    _userRoleRepository.Where(p => p.UserId == userId).Select(p => p.RoleId).ToList();
            }

            return new
            {
                user= userProfile,
                posts=_postRepository.DetachedEntities.ToList(),
                roles = _roleRepository.DetachedEntities.ToList()
            };
        }
        [SecurityDefine(SecurityConsts.USER_SERVICE_EDIT)]
        public async Task UpdateAsync(UserProfile user)
        {
            var updateUser = user.Adapt<SysUser>();
            using (var transaction = _userRepository.Database.BeginTransaction())
            {
                try
                {
                    await _userRepository.UpdateExcludeAsync(updateUser, new[] { nameof(SysUser.IsDeleted), nameof(SysUser.CreatedTime) }, ignoreNullValues: true);
                    SavePostOrRoleInfo(user);
                    // 提交事务
                    transaction.Commit();
                }
                catch (Exception e)
                {
                    // 回滚事务
                    transaction.Rollback();
                    throw;
                }
            }

            
        }

        private void SavePostOrRoleInfo(UserProfile userDto)
        {
            if (userDto.postIds != null && userDto.postIds.Count > 0)
            {
                var rowEffects = $"delete from sysuserpost where UserId={userDto.Id}".SqlNonQuery();

                _userPostRepository.InsertNow(
                    userDto.postIds.Select(p => new SysUserPost() { PostId = p, UserId = userDto.Id }));

            }
            if (userDto.roleIds != null && userDto.roleIds.Count > 0)
            {
                var rowEffects = $"delete from sysuserrole where RoleId={userDto.Id}".SqlNonQuery();

                _userRoleRepository.InsertNow(
                    userDto.roleIds.Select(p => new SysUserRole() {  RoleId= p, UserId = userDto.Id }));
            }
        }

        public async Task DeleteAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的用户 Id")] int userId)
        {
            var deleteMenu = await _userRepository.FindAsync(userId);
            _ = deleteMenu ?? throw Oops.Oh(SystemErrorCodes.u1002);

            // 软/假删除
            deleteMenu.IsDeleted = true;
        }

        public Task UpdateChangeUserStatus(ModifyPwdOrStatusInput modifyPwdOrStatus)
        {
            throw new NotImplementedException();
        }

        public Task UpdateResetUserPwd(ModifyPwdOrStatusInput modifyPwdOrStatus)
        {
            throw new NotImplementedException();
        }
    }
}
